package utils

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"

	"github.com/inntu/backend/config"
	"github.com/tencentyun/cos-go-sdk-v5"
)

// COSClient COS客户端封装
type COSClient struct {
	client *cos.Client
	config *config.Config
}

// ObjectInfo 对象信息结构体
type ObjectInfo struct {
	Key          string            `json:"key"`
	Size         int64             `json:"size"`
	LastModified time.Time         `json:"last_modified"`
	ETag         string            `json:"etag"`
	ContentType  string            `json:"content_type"`
	Metadata     map[string]string `json:"metadata"`
}

// UploadOptions 上传选项
type UploadOptions struct {
	ContentType string            `json:"content_type"`
	Metadata    map[string]string `json:"metadata"`
	ACL         string            `json:"acl"` // private, public-read, public-read-write
}

// DownloadOptions 下载选项
type DownloadOptions struct {
	Range string `json:"range"` // 例如: "bytes=0-1023"
}

// NewCOSClient 创建COS客户端
func NewCOSClient(profile string) (*COSClient, error) {
	cfg, err := config.NewConfig(profile, "dev") // 使用指定的COS profile和dev环境
	if err != nil {
		return nil, fmt.Errorf("加载配置失败: %v", err)
	}

	// 构建bucket URL
	u, err := url.Parse(cfg.COS.BUCKETURL)
	if err != nil {
		return nil, fmt.Errorf("解析bucket URL失败: %v", err)
	}

	b := &cos.BaseURL{BucketURL: u}
	c := cos.NewClient(b, &http.Client{
		Transport: &cos.AuthorizationTransport{
			SecretID:  cfg.COS.SECRETID,
			SecretKey: cfg.COS.SECRETKEY,
		},
	})

	return &COSClient{
		client: c,
		config: cfg,
	}, nil
}

// PutObject 上传对象
func (c *COSClient) PutObject(ctx context.Context, key string, reader io.Reader, opts *UploadOptions) error {
	var putOpts *cos.ObjectPutOptions
	if opts != nil {
		putOpts = &cos.ObjectPutOptions{
			ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{},
			ACLHeaderOptions:       &cos.ACLHeaderOptions{},
		}

		// 设置Content-Type
		if opts.ContentType != "" {
			putOpts.ObjectPutHeaderOptions.ContentType = opts.ContentType
		}

		// 设置自定义元数据
		if len(opts.Metadata) > 0 {
			header := make(http.Header)
			for k, v := range opts.Metadata {
				header.Set("x-cos-meta-"+k, v)
			}
			putOpts.ObjectPutHeaderOptions.XCosMetaXXX = &header
		}

		// 设置ACL
		if opts.ACL != "" {
			putOpts.ACLHeaderOptions.XCosACL = opts.ACL
		}
	}

	_, err := c.client.Object.Put(ctx, key, reader, putOpts)
	return err
}

// PutObjectFromFile 从文件上传对象
func (c *COSClient) PutObjectFromFile(ctx context.Context, key, filePath string, opts *UploadOptions) error {
	file, err := os.Open(filePath)
	if err != nil {
		return fmt.Errorf("打开文件失败: %v", err)
	}
	defer file.Close()

	return c.PutObject(ctx, key, file, opts)
}

// GetObject 下载对象到Reader
func (c *COSClient) GetObject(ctx context.Context, key string, opts *DownloadOptions) (io.ReadCloser, error) {
	var getOpts *cos.ObjectGetOptions
	if opts != nil {
		getOpts = &cos.ObjectGetOptions{}
		if opts.Range != "" {
			getOpts.Range = opts.Range
		}
	}

	resp, err := c.client.Object.Get(ctx, key, getOpts)
	if err != nil {
		return nil, err
	}

	return resp.Body, nil
}

// GetObjectToFile 下载对象到文件
func (c *COSClient) GetObjectToFile(ctx context.Context, key, filePath string, opts *DownloadOptions) error {
	var getOpts *cos.ObjectGetOptions
	if opts != nil {
		getOpts = &cos.ObjectGetOptions{}
		if opts.Range != "" {
			getOpts.Range = opts.Range
		}
	}

	_, err := c.client.Object.GetToFile(ctx, key, filePath, getOpts)
	return err
}

// HeadObject 获取对象元信息
func (c *COSClient) HeadObject(ctx context.Context, key string) (*ObjectInfo, error) {
	resp, err := c.client.Object.Head(ctx, key, nil)
	if err != nil {
		return nil, err
	}

	// 解析Last-Modified时间
	lastModified, _ := time.Parse(time.RFC1123, resp.Header.Get("Last-Modified"))

	// 提取自定义元数据
	metadata := make(map[string]string)
	for k, v := range resp.Header {
		if strings.HasPrefix(strings.ToLower(k), "x-cos-meta-") {
			metaKey := strings.TrimPrefix(strings.ToLower(k), "x-cos-meta-")
			if len(v) > 0 {
				metadata[metaKey] = v[0]
			}
		}
	}

	return &ObjectInfo{
		Key:          key,
		Size:         resp.ContentLength,
		LastModified: lastModified,
		ETag:         strings.Trim(resp.Header.Get("ETag"), `"`),
		ContentType:  resp.Header.Get("Content-Type"),
		Metadata:     metadata,
	}, nil
}

// DeleteObject 删除对象
func (c *COSClient) DeleteObject(ctx context.Context, key string) error {
	_, err := c.client.Object.Delete(ctx, key)
	return err
}

// IsObjectExist 检查对象是否存在
func (c *COSClient) IsObjectExist(ctx context.Context, key string) (bool, error) {
	return c.client.Object.IsExist(ctx, key)
}

// CopyObject 复制对象
func (c *COSClient) CopyObject(ctx context.Context, destKey, sourceKey string) error {
	// 构建源对象URL: bucket-name/object-key
	sourceURL := fmt.Sprintf("%s/%s", c.config.COS.BUCKET, sourceKey)

	_, _, err := c.client.Object.Copy(ctx, destKey, sourceURL, nil)
	return err
}

// GetObjectURL 获取对象的访问URL
func (c *COSClient) GetObjectURL(key string) string {
	return c.client.Object.GetObjectURL(key).String()
}

// GetPresignedURL 获取预签名URL
func (c *COSClient) GetPresignedURL(ctx context.Context, method, key string, expired time.Duration) (string, error) {
	presignedURL, err := c.client.Object.GetPresignedURL(
		ctx,
		method,
		key,
		c.config.COS.SECRETID,
		c.config.COS.SECRETKEY,
		expired,
		nil,
	)
	if err != nil {
		return "", err
	}
	return presignedURL.String(), nil
}

// SetObjectACL 设置对象ACL权限
func (c *COSClient) SetObjectACL(ctx context.Context, key, acl string) error {
	opts := &cos.ObjectPutACLOptions{
		Header: &cos.ACLHeaderOptions{
			XCosACL: acl, // private, public-read, public-read-write
		},
	}
	_, err := c.client.Object.PutACL(ctx, key, opts)
	return err
}

// GetObjectACL 获取对象ACL权限
func (c *COSClient) GetObjectACL(ctx context.Context, key string) (*cos.ObjectGetACLResult, error) {
	result, _, err := c.client.Object.GetACL(ctx, key)
	return result, err
}

// LogError 统一的错误日志处理
func LogError(err error) {
	if err == nil {
		return
	}
	if cos.IsNotFoundError(err) {
		fmt.Println("WARN: 资源不存在")
	} else if e, ok := cos.IsCOSError(err); ok {
		fmt.Printf("COS错误 - Code: %v, Message: %v, RequestId: %v\n", e.Code, e.Message, e.RequestID)
	} else {
		fmt.Printf("错误: %v\n", err)
	}
}
